package subscription

import (
	"context"
	"encoding/json"
	"fmt"
	"git.mycaigou.com/gfyx/common/http_client"
	"git.mycaigou.com/gfyx/common/simplecopier"
	"git.mycaigou.com/gfyx/common/tenant_db"
	"git.mycaigou.com/gfyx/common/usermetadata"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/constants"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/msg_center"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/utils"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/base/msg"
	userRepo "git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/base/user"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/business_opportunity/contact"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/business_opportunity/subscription/push_config"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/business_opportunity/subscription/push_log"
	radar2 "git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/business_opportunity/subscription/radar"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/remote/gfyx_user_service_remote"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/remote/opensearch_remote"
	businessOpportunityPb "git.mycaigou.com/gfyx/micro-gfyx-oppty-service/proto/micro_gfyx_oppty_service_proto/micro-gfyx-oppty-service/business_opportunity"
	tenantPb "git.mycaigou.com/gfyx/micro-gfyx-oppty-service/proto/micro_gfyx_user_service_proto/micro-gfyx-user-service/tenant"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/service/business_opportunity/oppty_status"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/service/common/option"
	"git.myscrm.cn/golang/stark/v4"
	"strings"
	"time"
)

type subscriptionService struct {
	radarSubscriptionConfigRepos radar2.GfyxRadarSubscriptionConfigReposIface
	subscriptionPushConfigRepos  push_config.GfyxSubscriptionPushConfigReposIface
	userBindRepos                userRepo.GfyxUserBindReposIface
	userNewRepos                 userRepo.UserRepositoryIface
	openSearchRepos              opensearch_remote.OpenSearchRepositoryIface
	opptyStatusService           oppty_status.OpptyStatusServiceIface
	opTelViewHistoryRepos        contact.GfyxOpTelViewHistoryReposIface
	msgRepo                      msg.MsgRepositoryIface
	pushLogRepos                 push_log.GfyxRadarSubscriptionPushLogReposIface
	optionService                option.OptionServiceIface
	gfyxUserServiceRepo          gfyx_user_service_remote.GfyxUserServiceRepositoryIface
}

func NewSubscriptionService(
	RadarSubscriptionConfigRepos radar2.GfyxRadarSubscriptionConfigReposIface,
	SubscriptionPushConfigRepos push_config.GfyxSubscriptionPushConfigReposIface,
	UserBIndRepos userRepo.GfyxUserBindReposIface,
	userNewRepos userRepo.UserRepositoryIface,
	openSearchRepos opensearch_remote.OpenSearchRepositoryIface,
	opptyStatusService oppty_status.OpptyStatusServiceIface,
	opTelViewHistoryRepos contact.GfyxOpTelViewHistoryReposIface,
	msgRepo msg.MsgRepositoryIface,
	pushLogRepos push_log.GfyxRadarSubscriptionPushLogReposIface,
	optionService option.OptionServiceIface,
	gfyxUserServiceRepo gfyx_user_service_remote.GfyxUserServiceRepositoryIface,
) SubscriptionServiceIface {
	return &subscriptionService{
		radarSubscriptionConfigRepos: RadarSubscriptionConfigRepos,
		subscriptionPushConfigRepos:  SubscriptionPushConfigRepos,
		userBindRepos:                UserBIndRepos,
		userNewRepos:                 userNewRepos,
		openSearchRepos:              openSearchRepos,
		opptyStatusService:           opptyStatusService,
		opTelViewHistoryRepos:        opTelViewHistoryRepos,
		msgRepo:                      msgRepo,
		pushLogRepos:                 pushLogRepos,
		optionService:                optionService,
		gfyxUserServiceRepo:          gfyxUserServiceRepo,
	}
}

// GetRadarSubscriptionConfig 获取线索雷达订阅设置
func (f *subscriptionService) GetRadarSubscriptionConfig(ctx context.Context, request *businessOpportunityPb.GetRadarSubscriptionConfigRequest) (*businessOpportunityPb.GetRadarSubscriptionConfigResponse, error) {
	metaUserInfo := usermetadata.GetMetaUserInfo(ctx)
	result, err := f.radarSubscriptionConfigRepos.GetRadarSubscriptionConfigByUser(ctx, metaUserInfo.TenantUserUid)
	if err != nil {
		stark.Logger.Error(ctx, "GetRadarSubscriptionConfig err:", err)
		return nil, err
	}
	data := &businessOpportunityPb.GetRadarSubscriptionConfigResponse{}
	if result.Id == 0 {
		result.IsBuildingOpen = 1 //默认开启
		result.IsSaleOpen = 1     //默认开启
		result.IsLandOpen = 1     //默认开启

		resultAdmin, errAdmin := f.radarSubscriptionConfigRepos.GetRadarSubscriptionConfigByUser(ctx, constants.AdminUserGUID)
		if errAdmin != nil {
			stark.Logger.Error(ctx, "GetRadarSubscriptionConfig err:", err)
			return nil, err
		}
		if resultAdmin.Id != 0 {
			result.BidKeyword = resultAdmin.BidKeyword
			result.WinbidKeyword = resultAdmin.WinbidKeyword
			result.BidKeywordExclude = resultAdmin.BidKeywordExclude
			result.ProjectKeyword = resultAdmin.ProjectKeyword
			result.LandUsage = resultAdmin.LandUsage
			result.SaleType = resultAdmin.SaleType
			result.BuildingType = resultAdmin.BuildingType
			result.IsBuildingOpen = resultAdmin.IsBuildingOpen
			result.IsLandOpen = resultAdmin.IsLandOpen
			result.IsSaleOpen = resultAdmin.IsSaleOpen
		}

	}
	_ = simplecopier.CopyToStruct(data, result)
	data.CreatedOn = result.CreatedOn.Format("2006-01-02 15:04:05")
	data.ModifiedOn = result.ModifiedOn.Format("2006-01-02 15:04:05")

	if data.AreaCode != "" {
		radarAreaOption, err := f.optionService.GetRadarAreaOption(ctx)
		if err != nil {
			stark.Logger.Error(ctx, "GetSubscriptionPushConfig err:", err)
			return nil, err
		}

		radarAreaCodeMap := make(map[string]bool)
		if radarAreaOption != nil && len(radarAreaOption.Options) > 0 {
			for _, item := range radarAreaOption.Options {
				radarAreaCodeMap[item.AreaCode] = true
			}
		}

		var resultAreaCodes []string
		areaCodeList := strings.Split(data.AreaCode, ",")
		for _, areaCodeItem := range areaCodeList {
			if _, ok := radarAreaCodeMap[areaCodeItem]; ok {
				resultAreaCodes = append(resultAreaCodes, areaCodeItem)
			}
		}

		data.AreaCode = strings.Join(resultAreaCodes, ",")
	}

	//获取云采购公众号openid
	userBind, err := f.userBindRepos.GetUserBind(ctx, metaUserInfo.TenantUserUid)
	if err != nil {
		stark.Logger.Error(ctx, "获取user_bind表,err:%s", err.Error())
	}
	if userBind != nil && userBind.OpenId == "" && metaUserInfo.MobilePhone != "" {
		openApiUserSubscribeRequest := &OpenApiUserSubscribeRequest{
			AppId:   stark.Configer.(stark.ApolloConfigerIface).GetStringValue(constants.YcgGzhAppId, "wx26f077d201e7c978"),
			Mobile:  metaUserInfo.MobilePhone,
			UnionId: request.UnionId,
		}
		openApiUserSubscribeRequestMap, err := simplecopier.StructToMapByJsonTag(openApiUserSubscribeRequest)
		if err != nil {
			stark.Logger.Error(ctx, "结构体转map异常,err:%s", err.Error())
		}
		resultData := &OpenApiUserSubscribeResponse{}
		_, _, errs := http_client.NewOpenApiHttpClient().Post(ctx, constants.OpenApiPathGetUserSubscriptionInfo, openApiUserSubscribeRequestMap, map[string]string{}).EndStruct(&resultData)
		if len(errs) > 0 {
			stark.Logger.Error(ctx, "获取open_api接口异常,接口:%s,err:%s", constants.OpenApiPathGetUserSubscriptionInfo, errs[0].Error())
		}
		if resultData.Success && resultData.Data.OpenID != "" && resultData.Data.IsSubscribe == 1 {
			//是已订阅状态
			userBind.OpenId = resultData.Data.OpenID
			userBind.UserGuid = metaUserInfo.TenantUserUid
			userBind.UnionId = resultData.Data.UnionId
			userBind.Mobile = metaUserInfo.MobilePhone
			if userBind.Id == 0 {
				err := f.userBindRepos.AddUserBind(ctx, userBind)
				if err != nil {
					stark.Logger.Error(ctx, "新增gfyx_user_bind异常,err:%s", err.Error())
				}
			} else {
				err := f.userBindRepos.SaveUserBind(ctx, userBind)
				if err != nil {
					stark.Logger.Error(ctx, "保存gfyx_user_bind异常,err:%s", err.Error())
				}
			}

		}
	}

	return data, nil
}

// SaveRadarSubscriptionConfig 保存线索雷达订阅设置
func (f *subscriptionService) SaveRadarSubscriptionConfig(ctx context.Context, request *businessOpportunityPb.SaveRadarSubscriptionConfigRequest) (*businessOpportunityPb.SaveRadarSubscriptionConfigResponse, error) {
	metaUserInfo := usermetadata.GetMetaUserInfo(ctx)
	result, err := f.radarSubscriptionConfigRepos.GetRadarSubscriptionConfigByUser(ctx, metaUserInfo.TenantUserUid)
	if err != nil {
		stark.Logger.Error(ctx, "GetRadarSubscriptionConfig err:", err)
		return nil, err
	}

	if result.UserGuid == "" {
		_ = simplecopier.CopyToStruct(result, request)
		result.UserGuid = metaUserInfo.TenantUserUid
		err := f.radarSubscriptionConfigRepos.AddRadarSubscriptionConfig(ctx, result)
		if err != nil {
			stark.Logger.Error(ctx, "新增gfyx_radar_subscription_config表异常,err:%s", err.Error())
		}

	} else {
		result.LandUsage = request.LandUsage
		result.IsLandOpen = request.IsLandOpen
		result.SaleType = request.SaleType
		result.IsSaleOpen = request.IsSaleOpen
		result.BuildingType = request.BuildingType
		result.IsBuildingOpen = request.IsBuildingOpen
		result.BidKeyword = request.BidKeyword
		result.WinbidKeyword = request.WinbidKeyword
		result.ProjectKeyword = request.ProjectKeyword
		result.BidKeywordExclude = request.BidKeywordExclude
		result.AreaCode = request.AreaCode
		err := f.radarSubscriptionConfigRepos.SaveRadarSubscriptionConfig(ctx, result)
		if err != nil {
			stark.Logger.Error(ctx, "更新gfyx_radar_subscription_config表异常,err:%s", err.Error())
		}
	}

	data := &businessOpportunityPb.SaveRadarSubscriptionConfigResponse{
		Success: true,
	}
	return data, nil
}

// GetSubscriptionPushConfig 获取订阅推送设置
func (f *subscriptionService) GetSubscriptionPushConfig(ctx context.Context, _ *businessOpportunityPb.GetSubscriptionPushConfigRequest) (*businessOpportunityPb.GetSubscriptionPushConfigResponse, error) {
	metaUserInfo := usermetadata.GetMetaUserInfo(ctx)
	result, err := f.subscriptionPushConfigRepos.GetSubscriptionPushConfigByUser(ctx, metaUserInfo.TenantUserUid)
	if err != nil {
		stark.Logger.Error(ctx, "GetSubscriptionPushConfig err:", err)
		return nil, err
	}
	data := &businessOpportunityPb.GetSubscriptionPushConfigResponse{}
	_ = simplecopier.CopyToStruct(data, result)
	data.CreatedOn = result.CreatedOn.Format("2006-01-02 15:04:05")
	data.ModifiedOn = result.ModifiedOn.Format("2006-01-02 15:04:05")
	return data, nil
}

// SaveSubscriptionPushConfig 保存订阅推送设置
func (f *subscriptionService) SaveSubscriptionPushConfig(ctx context.Context, request *businessOpportunityPb.SaveSubscriptionPushConfigRequest) (*businessOpportunityPb.SaveSubscriptionPushConfigResponse, error) {
	metaUserInfo := usermetadata.GetMetaUserInfo(ctx)
	result, err := f.subscriptionPushConfigRepos.GetSubscriptionPushConfigByUser(ctx, metaUserInfo.TenantUserUid)
	if err != nil {
		stark.Logger.Error(ctx, "SaveSubscriptionPushConfig err:", err)
		return nil, err
	}
	result.PushTime = constants.SubscriptionPushTime //默认
	result.Period = constants.SubscriptionPeriod     //默认
	if result.UserGuid == "" {
		result.Email = request.Email
		result.UserGuid = metaUserInfo.TenantUserUid
		err := f.subscriptionPushConfigRepos.AddSubscriptionPushConfig(ctx, result)
		if err != nil {
			stark.Logger.Error(ctx, "新增gfyx_subscription_push_config表异常,err:%s", err.Error())
		}

	} else {
		result.Email = request.Email
		err := f.subscriptionPushConfigRepos.SaveSubscriptionPushConfig(ctx, result)
		if err != nil {
			stark.Logger.Error(ctx, "更新gfyx_subscription_push_config表异常,err:%s", err.Error())
		}
	}

	data := &businessOpportunityPb.SaveSubscriptionPushConfigResponse{
		Success: true,
	}
	return data, nil
}

type OpenApiUserSubscribeRequest struct {
	AppId   string `json:"app_id"`
	Mobile  string `json:"mobile"`
	UnionId string `json:"unionid"`
}
type OpenApiUserSubscribeResponse struct {
	Success   bool   `json:"success"`
	Message   string `json:"message"`
	ErrorCode string `json:"errorCode"`
	Data      struct {
		IsSubscribe   int    `json:"is_subscribe"`
		SubscribeTime string `json:"subscribe_time"`
		OpenID        string `json:"open_id"`
		UnionId       string `json:"unionid"`
		UserID        string `json:"user_id"`
	} `json:"data"`
}

type YcgMobileGenerateQrCodeRequest struct {
	SceneId string `json:"scene_id"`
}
type YcgMobileGenerateQrCodeResponse struct {
	Success   bool   `json:"success"`
	Message   string `json:"message"`
	ErrorCode string `json:"errorCode"`
	Data      struct {
		SceneId   string `json:"scene_id"`
		QrCodeUrl string `json:"qr_code_url"`
	} `json:"data"`
}

func (f *subscriptionService) createSceneId() string {
	timestamp := time.Now().Unix()
	res := fmt.Sprintf("%s%d", "supplier_saas_", timestamp)
	return res
}

// GetWxQrCode 获取公众号二维码
func (f *subscriptionService) GetWxQrCode(ctx context.Context, request *businessOpportunityPb.GetWxQrCodeRequest) (*businessOpportunityPb.GetWxQrCodeResponse, error) {
	metaUserInfo := usermetadata.GetMetaUserInfo(ctx)
	sceneId := f.createSceneId()
	returnData := &businessOpportunityPb.GetWxQrCodeResponse{
		AttentionStatus: 0,
		SceneId:         sceneId,
	}
	userBind, err := f.userBindRepos.GetUserBind(ctx, metaUserInfo.TenantUserUid)
	if err != nil {
		stark.Logger.Error(ctx, "获取user_bind表,err:%s", err.Error())
	}
	if userBind != nil && userBind.OpenId != "" { //绑定表已有数据
		returnData.AttentionStatus = 1
		returnData.UnionId = userBind.UnionId
	} else {
		if metaUserInfo.MobilePhone == "" {
			return returnData, nil
		}
		//1、根据手机号获取公众号绑定状态
		openApiUserSubscribeRequest := &OpenApiUserSubscribeRequest{
			AppId:   stark.Configer.(stark.ApolloConfigerIface).GetStringValue(constants.YcgGzhAppId, "wx26f077d201e7c978"),
			Mobile:  metaUserInfo.MobilePhone,
			UnionId: request.UnionId,
			//Mobile: "13751174461",
		}
		openApiUserSubscribeRequestMap, err := simplecopier.StructToMapByJsonTag(openApiUserSubscribeRequest)
		if err != nil {
			stark.Logger.Error(ctx, "结构体转map异常,err:%s", err.Error())
		}
		resultData := &OpenApiUserSubscribeResponse{}
		_, _, errs := http_client.NewOpenApiHttpClient().Post(ctx, constants.OpenApiPathGetUserSubscriptionInfo, openApiUserSubscribeRequestMap, map[string]string{}).EndStruct(&resultData)
		if len(errs) > 0 {
			stark.Logger.Error(ctx, "获取open_api接口异常,接口:%s,err:%s", constants.OpenApiPathGetUserSubscriptionInfo, errs[0].Error())
		}
		if !resultData.Success {
			return returnData, nil
		}

		//2、如果已关注，保存openid，否则，返回公众号二维码
		if resultData.Data.OpenID != "" && resultData.Data.IsSubscribe == 1 { //是已订阅状态
			userBind, err := f.userBindRepos.GetUserBind(ctx, metaUserInfo.TenantUserUid)
			if err != nil {
				stark.Logger.Error(ctx, "获取gfyx_user_bind异常,err:%s", err.Error())
			}
			if userBind != nil {
				userBind.OpenId = resultData.Data.OpenID
				userBind.UserGuid = metaUserInfo.TenantUserUid
				userBind.UnionId = resultData.Data.UnionId
				userBind.Mobile = metaUserInfo.MobilePhone
				if userBind.UserGuid == "" {
					err := f.userBindRepos.AddUserBind(ctx, userBind)
					if err != nil {
						stark.Logger.Error(ctx, "新增gfyx_user_bind异常,err:%s", err.Error())
					}
				} else {
					err := f.userBindRepos.SaveUserBind(ctx, userBind)
					if err != nil {
						stark.Logger.Error(ctx, "保存gfyx_user_bind异常,err:%s", err.Error())
					}
				}
			}
			returnData.AttentionStatus = 1
			returnData.UnionId = resultData.Data.UnionId
			return returnData, nil
		}

	}

	ycgMobileGenerateQrCodeRequest := &YcgMobileGenerateQrCodeRequest{
		SceneId: sceneId,
	}
	ycgMobileGenerateQrCodeRequestMap, err := simplecopier.StructToMapByJsonTag(ycgMobileGenerateQrCodeRequest)
	if err != nil {
		stark.Logger.Error(ctx, "结构体转map异常,err:%s", err.Error())
	}
	ycgMobileGenerateQrCodeResponse := &YcgMobileGenerateQrCodeResponse{}
	_, _, errs := http_client.NewYcgMobileClient().Post(ctx, "/api/wechat/ycg/generate-qr-code", ycgMobileGenerateQrCodeRequestMap, map[string]string{}).EndStruct(&ycgMobileGenerateQrCodeResponse)
	if len(errs) > 0 {
		stark.Logger.Error(ctx, "获取m.b2b接口异常,接口:%s,err:%s", "/api/wechat/ycg/generate-qr-code", errs[0].Error())
	}
	if ycgMobileGenerateQrCodeResponse.Success {
		returnData.QrCodeUrl = ycgMobileGenerateQrCodeResponse.Data.QrCodeUrl
	}

	return returnData, nil
}

// BindOpenIdByCard GetWxQrCode 获取公众号二维码
func (f *subscriptionService) BindOpenIdByCard(ctx context.Context, request *businessOpportunityPb.BindOpenIdByCardRequest) (*businessOpportunityPb.BindOpenIdByCardResponse, error) {
	if request.YcgOpenid == "" {
		return &businessOpportunityPb.BindOpenIdByCardResponse{}, nil
	}
	stark.Logger.Infof(ctx, "BindOpenIdByCard 绑定ycg_openid,值:%s", request.YcgOpenid)
	metaUserInfo := usermetadata.GetMetaUserInfo(ctx)
	userBind, err := f.userBindRepos.GetUserBind(ctx, metaUserInfo.TenantUserUid)
	if err != nil {
		stark.Logger.Error(ctx, "获取user_bind表,err:%s", err.Error())
	}
	res := &businessOpportunityPb.BindOpenIdByCardResponse{}
	if userBind != nil {
		if userBind.Id == 0 {
			userBind.OpenId = request.YcgOpenid
			userBind.UserGuid = metaUserInfo.TenantUserUid
			userBind.Mobile = metaUserInfo.MobilePhone
			err := f.userBindRepos.AddUserBind(ctx, userBind)
			if err != nil {
				stark.Logger.Error(ctx, "新增gfyx_user_bind异常,err:%s", err.Error())
			}
			res.IsNew = true
		} else if userBind.OpenId == "" {
			userBind.OpenId = request.YcgOpenid
			err := f.userBindRepos.SaveUserBind(ctx, userBind)
			if err != nil {
				stark.Logger.Error(ctx, "保存gfyx_user_bind异常,err:%s", err.Error())
			}
			res.IsNew = false
		}
	}
	return res, nil
}

type YcgMobileGetFollowStatusRequest struct {
	SceneId string `json:"scene_id"`
}
type YcgMobileGetFollowStatusResponse struct {
	Success   bool   `json:"success"`
	Message   string `json:"message"`
	ErrorCode string `json:"errorCode"`
	Data      struct {
		OpenId string `json:"open_id"`
	} `json:"data"`
}

type GetUnionIdRequest struct {
	AppId  string `json:"app_id"`
	OpenId string `json:"openid"`
}
type GetUnionIdResponse struct {
	Success   bool   `json:"success"`
	Message   string `json:"message"`
	ErrorCode string `json:"errorCode"`
	Data      struct {
		IsSubscribe   int    `json:"is_subscribe"`
		SubscribeTime string `json:"subscribe_time"`
		OpenID        string `json:"open_id"`
		UnionId       string `json:"unionid"`
		UserID        string `json:"user_id"`
	} `json:"data"`
}

// GetBindStatus 获取公众号关注状态
func (f *subscriptionService) GetBindStatus(ctx context.Context, request *businessOpportunityPb.GetBindStatusRequest) (*businessOpportunityPb.GetBindStatusResponse, error) {
	metaUserInfo := usermetadata.GetMetaUserInfo(ctx)
	returnData := &businessOpportunityPb.GetBindStatusResponse{
		AttentionStatus: 0,
		SceneId:         request.SceneId,
	}
	//1、绑定表
	userBind, err := f.userBindRepos.GetUserBind(ctx, metaUserInfo.TenantUserUid)
	if err != nil {
		stark.Logger.Error(ctx, "获取user_bind表,err:%s", err.Error())
	}
	if userBind != nil && userBind.OpenId != "" { //绑定表已有数据
		returnData.AttentionStatus = 1
		returnData.OpenId = userBind.OpenId
		returnData.UnionId = userBind.UnionId
	}
	//2、查询场景值有没有被关注
	ycgMobileGetFollowStatusRequest := &YcgMobileGetFollowStatusRequest{
		SceneId: request.SceneId,
	}
	ycgMobileGetFollowStatusRequestMap, err := simplecopier.StructToMapByJsonTag(ycgMobileGetFollowStatusRequest)
	if err != nil {
		stark.Logger.Error(ctx, "结构体转map异常,err:%s", err.Error())
	}
	ycgMobileGetFollowStatusResponse := &YcgMobileGetFollowStatusResponse{}
	_, _, errs := http_client.NewYcgMobileClient().Get(ctx, "/api/wechat/ycg/get-follow-status", ycgMobileGetFollowStatusRequestMap).EndStruct(&ycgMobileGetFollowStatusResponse)
	if len(errs) > 0 {
		stark.Logger.Error(ctx, "获取m.b2b接口异常,接口:%s,err:%s", "/api/wechat/ycg/get-follow-status", errs[0].Error())
	}
	//如果已关注，则返回openid，AttentionStatus=1
	if ycgMobileGetFollowStatusResponse.Success && ycgMobileGetFollowStatusResponse.Data.OpenId != "" {
		returnData.AttentionStatus = 1
		returnData.OpenId = ycgMobileGetFollowStatusResponse.Data.OpenId
		//保存openid
		userBind, err := f.userBindRepos.GetUserBind(ctx, metaUserInfo.TenantUserUid)
		if err != nil {
			stark.Logger.Error(ctx, "获取gfyx_user_bind异常,err:%s", err.Error())
		}
		if userBind != nil {
			userBind.OpenId = ycgMobileGetFollowStatusResponse.Data.OpenId
			userBind.UserGuid = metaUserInfo.TenantUserUid
			userBind.Mobile = metaUserInfo.MobilePhone
			if userBind.UserGuid == "" {
				err := f.userBindRepos.AddUserBind(ctx, userBind)
				if err != nil {
					stark.Logger.Error(ctx, "新增gfyx_user_bind异常,err:%s", err.Error())
				}
			} else {
				err := f.userBindRepos.SaveUserBind(ctx, userBind)
				if err != nil {
					stark.Logger.Error(ctx, "保存gfyx_user_bind异常,err:%s", err.Error())
				}
			}
		}
	}
	//3、根据跟openid补充union_id
	if returnData.OpenId != "" {
		getUnionIdRequest := &GetUnionIdRequest{
			AppId:  stark.Configer.(stark.ApolloConfigerIface).GetStringValue(constants.YcgGzhAppId, "wx26f077d201e7c978"),
			OpenId: returnData.OpenId,
		}
		getUnionIdRequestMap, err := simplecopier.StructToMapByJsonTag(getUnionIdRequest)
		if err != nil {
			stark.Logger.Error(ctx, "结构体转map异常,err:%s", err.Error())
		}
		resultDataUnionId := &OpenApiUserSubscribeResponse{}
		_, _, errsGetUnionId := http_client.NewOpenApiHttpClient().Post(ctx, constants.OpenApiPathGetUserSubscriptionInfoByOpenId, getUnionIdRequestMap, map[string]string{}).EndStruct(&resultDataUnionId)
		if len(errsGetUnionId) > 0 {
			stark.Logger.Error(ctx, "获取union_api接口异常,接口:%s,err:%s", constants.OpenApiPathGetUserSubscriptionInfoByOpenId, errsGetUnionId[0].Error())
		}
		if resultDataUnionId.Success && resultDataUnionId.Data.UnionId != "" {
			returnData.UnionId = resultDataUnionId.Data.UnionId
			_, err := f.userBindRepos.UpdateUnionId(ctx, returnData.OpenId, metaUserInfo.TenantUserUid, resultDataUnionId.Data.UnionId)
			if err != nil {
				stark.Logger.Error(ctx, "更新union_id,err:%s", err.Error())
			}
		}
	}

	return returnData, nil
}

func (f *subscriptionService) buildRadarRequestParamsWithSubscriptionConfig(ctx context.Context, request *businessOpportunityPb.GetRadarListRequest) (*opensearch_remote.GetRadarListRequest, *radar2.GfyxRadarSubscriptionConfig, error) {
	metaUserInfo := usermetadata.GetMetaUserInfo(ctx)
	radarSubscriptionConfigPo, err := f.radarSubscriptionConfigRepos.GetRadarSubscriptionConfigByUser(ctx, metaUserInfo.TenantUserUid)
	if err != nil {
		return nil, nil, err
	}

	params := &opensearch_remote.GetRadarListRequest{
		AreaCode:  request.AreaCodes,
		StartTime: request.StartTime,
		EndTime:   request.EndTime,
		Page:      request.Page,
		PageSize:  request.PageSize,
	}

	for _, reqOpptyType := range request.OpptyType {
		opptyName := constants.GetOpptyTypeName(reqOpptyType)
		// 只有在建在es存的名字和前端页码展示的名字不一致
		if opptyName == constants.OpptyTypeBuildingName {
			opptyName = "在建"
		}
		params.DataType = append(params.DataType, opptyName)
	}

	if radarSubscriptionConfigPo != nil {
		if radarSubscriptionConfigPo.BidKeyword != "" {
			params.BidKeyword = utils.SplitStr(radarSubscriptionConfigPo.BidKeyword)
		}
		if radarSubscriptionConfigPo.WinbidKeyword != "" {
			params.WinbidKeyword = utils.SplitStr(radarSubscriptionConfigPo.WinbidKeyword) //strings.Split(radarSubscriptionConfigPo.WinbidKeyword, ",")
		}
		if radarSubscriptionConfigPo.BidKeywordExclude != "" {
			params.ExcludeKeyword = utils.SplitStr(radarSubscriptionConfigPo.BidKeywordExclude) //strings.Split(radarSubscriptionConfigPo.BidKeywordExclude, ",")
		}
		if radarSubscriptionConfigPo.BuildingType != "" {
			params.BuildingType = strings.Split(radarSubscriptionConfigPo.BuildingType, ",")
		}
		if radarSubscriptionConfigPo.SaleType != "" {
			params.SaleType = strings.Split(radarSubscriptionConfigPo.SaleType, ",")
		}
		if radarSubscriptionConfigPo.LandUsage != "" {
			params.LandUsageLabel = strings.Split(radarSubscriptionConfigPo.LandUsage, ",")
		}
		if radarSubscriptionConfigPo.ProjectKeyword != "" {
			params.ProjectKeyword = utils.SplitStr(radarSubscriptionConfigPo.ProjectKeyword) //strings.Split(radarSubscriptionConfigPo.ProjectKeyword, ",")
		}
		params.IsLandOpen = radarSubscriptionConfigPo.IsLandOpen
		params.IsBuildingOpen = radarSubscriptionConfigPo.IsBuildingOpen
		params.IsSaleOpen = radarSubscriptionConfigPo.IsSaleOpen
	}
	return params, radarSubscriptionConfigPo, nil
}

func (f *subscriptionService) getCompanyContact(ctx context.Context, radarData *opensearch_remote.GetRadarListData, radarSubscriptionConfigPo *radar2.GfyxRadarSubscriptionConfig) map[string][]*opensearch_remote.GetRadarContactData {
	var developerNameList []string
	var supplierNameList []string
	var mobileList []string
	metaUserInfo := usermetadata.GetMetaUserInfo(ctx)
	companyName2ContactList := make(map[string][]*opensearch_remote.GetRadarContactData)

	for _, item := range radarData.List {
		switch item.DataType {
		case "招标", "土地", "在建", "开盘":
			developerNameList = append(developerNameList, item.DeveloperName)
		case "中标":
			var suppliers []*businessOpportunityPb.SupplierItem
			_ = json.Unmarshal([]byte(item.Suppliers), &suppliers)
			for _, supplier := range suppliers {
				supplierNameList = append(supplierNameList, supplier.SupplierName)
			}
		}
	}

	// 获取联系人
	if len(developerNameList) != 0 {
		developerContactParams := &opensearch_remote.GetRadarContactRequest{
			CompanyName: developerNameList,
			IsDeveloper: 1,
			IsSupplier:  0,
		}
		if radarSubscriptionConfigPo.AreaCode != "" {
			developerContactParams.SubscriptAreaCode = strings.Split(radarSubscriptionConfigPo.AreaCode, ",")
		}
		if radarSubscriptionConfigPo.BidKeyword != "" {
			developerContactParams.BidKeyword = strings.Split(radarSubscriptionConfigPo.BidKeyword, ",")
		}
		developerContactList, err := f.openSearchRepos.GetRadarContact(ctx, developerContactParams)
		if err != nil {
			//获取不到联系人，不返回错误，不影响省市雷达列表的正常返回，记录错误日志即可
			stark.Logger.Errorf(ctx, "GetRadarList-GetRadarContact params:%+v, err:%s", developerContactParams, err.Error())
		}
		for _, contactData := range developerContactList {
			if contactData == nil {
				continue
			}
			if contactData.PhoneNumber != "" {
				mobileList = append(mobileList, contactData.PhoneNumber)
			}

			if contactList, ok := companyName2ContactList[contactData.CompanyName]; ok {
				contactExist := false
				for _, data := range contactList {
					if data.SourceId == contactData.SourceId {
						contactExist = true
					}
				}
				// 招标数据会先把招标负责人添加到结果集中，这里为避免联系人重复，加了这个判断
				if contactExist {
					continue
				}
				contactList = append(contactList, contactData)
				companyName2ContactList[contactData.CompanyName] = contactList
			} else {
				companyName2ContactList[contactData.CompanyName] = []*opensearch_remote.GetRadarContactData{contactData}
			}
		}
	}
	if len(supplierNameList) != 0 {
		supplierContactParams := &opensearch_remote.GetRadarContactRequest{
			CompanyName: supplierNameList,
			IsDeveloper: 0,
			IsSupplier:  1,
		}

		if radarSubscriptionConfigPo.AreaCode != "" {
			supplierContactParams.SubscriptAreaCode = strings.Split(radarSubscriptionConfigPo.AreaCode, ",")
		}
		if radarSubscriptionConfigPo.BidKeyword != "" {
			supplierContactParams.BidKeyword = strings.Split(radarSubscriptionConfigPo.BidKeyword, ",")
		}
		supplierContactList, err := f.openSearchRepos.GetRadarContact(ctx, supplierContactParams)
		if err != nil {
			//获取不到联系人，不返回错误，不影响省市雷达列表的正常返回，记录错误日志即可
			stark.Logger.Errorf(ctx, "GetRadarList-GetRadarContact params:%+v, err:%s", supplierContactParams, err.Error())
		}
		for _, contactData := range supplierContactList {
			if contactData == nil {
				continue
			}
			if contactData.PhoneNumber != "" {
				mobileList = append(mobileList, contactData.PhoneNumber)
			}
			if contactList, ok := companyName2ContactList[contactData.CompanyName]; ok {
				contactList = append(contactList, contactData)
				companyName2ContactList[contactData.CompanyName] = contactList
			} else {
				companyName2ContactList[contactData.CompanyName] = []*opensearch_remote.GetRadarContactData{contactData}
			}
		}
	}

	//获取手机号的查看次数
	mobileViewTimes, err := f.opTelViewHistoryRepos.GetOpTelViewHistoryBatch(ctx, mobileList, metaUserInfo.TenantUserUid)
	if err != nil {
		stark.Logger.Errorf(ctx, "GetRadarList-GetOpTelViewHistoryBatch params:%+v, userId:%s, err:%s", mobileList, metaUserInfo.TenantUserUid, err.Error())
	}

	for _, contactList := range companyName2ContactList {
		for _, contactData := range contactList {
			if viewCount, ok := mobileViewTimes[contactData.PhoneNumber]; ok {
				contactData.ViewTimes = viewCount
			} else {
				contactData.PhoneNumber = utils.GetMobileEncrypt(contactData.PhoneNumber)
			}
		}
	}

	return companyName2ContactList
}

func (f *subscriptionService) packingCompanyContract(_ context.Context, response *businessOpportunityPb.GetRadarListResponse, companyName2ContactList map[string][]*opensearch_remote.GetRadarContactData) {
	for _, item := range response.List {
		switch item.OpptyType {
		case constants.OpptyTypeBid, constants.OpptyTypeLand, constants.OpptyTypeBuilding, constants.OpptyTypeSale:
			contactList, ok := companyName2ContactList[item.DeveloperName]
			if ok {
				if len(item.Contactor) >= 2 {
					//只取2个联系人即可
					continue
				}
				for _, contactItem := range contactList {
					isExistContact := false
					for _, existContactItem := range item.Contactor {
						if existContactItem.SourceId == contactItem.SourceId {
							//contactItem已经存在，取contactList的下一个联系人
							isExistContact = true
							break
						}
					}
					if isExistContact {
						continue
					}

					if contactItem.Name == "" {
						contactItem.Name = "未知"
					}
					item.Contactor = append(item.Contactor, &businessOpportunityPb.ContactItem{
						CompanyName:    contactItem.CompanyName,
						OrganizingCode: contactItem.OrganizingCode,
						Name:           contactItem.Name,
						PhoneNumber:    contactItem.PhoneNumber,
						Position:       contactItem.Position,
						SourceId:       contactItem.SourceId,
						ViewTimes:      contactItem.ViewTimes,
						IsRecommend:    contactItem.IsRecommend,
					})
				}
			}
		case constants.OpptyTypeWinBid:
			for _, supplierItem := range item.Suppliers {
				contactList, ok := companyName2ContactList[supplierItem.SupplierName]
				if ok {
					if len(item.Contactor) >= 2 {
						//只取2个联系人即可
						continue
					}
					for _, contactItem := range contactList {
						isExistContact := false
						for _, existContactItem := range item.Contactor {
							if existContactItem.SourceId == contactItem.SourceId {
								//contactItem已经存在，取contactList的下一个联系人
								isExistContact = true
								break
							}
						}
						if isExistContact {
							continue
						}
						if contactItem.Name == "" {
							contactItem.Name = "未知"
						}
						item.Contactor = append(item.Contactor, &businessOpportunityPb.ContactItem{
							CompanyName:    contactItem.CompanyName,
							OrganizingCode: contactItem.OrganizingCode,
							Name:           contactItem.Name,
							PhoneNumber:    contactItem.PhoneNumber,
							Position:       contactItem.Position,
							SourceId:       contactItem.SourceId,
							ViewTimes:      contactItem.ViewTimes,
							IsRecommend:    contactItem.IsRecommend,
						})
					}
				}
			}
		}
	}

}

// GetRadarList 获取省市雷达列表
func (f *subscriptionService) GetRadarList(ctx context.Context, request *businessOpportunityPb.GetRadarListRequest) (*businessOpportunityPb.GetRadarListResponse, error) {
	metaUserInfo := usermetadata.GetMetaUserInfo(ctx)
	params, radarSubscriptionConfigPo, err := f.buildRadarRequestParamsWithSubscriptionConfig(ctx, request)
	if err != nil {
		return nil, err
	}
	radarData, err := f.openSearchRepos.GetRadarList(ctx, params)
	if err != nil {
		return nil, err
	}
	if radarData == nil {
		return &businessOpportunityPb.GetRadarListResponse{}, nil
	}

	radarPbResp := &businessOpportunityPb.GetRadarListResponse{
		Total:    radarData.Total,
		NewTotal: radarData.NewTotal,
	}

	companyName2ContactList := make(map[string][]*opensearch_remote.GetRadarContactData)
	//pc端需要获取联系人
	if strings.EqualFold(request.FromDevice, "PC") {
		companyName2ContactList = f.getCompanyContact(ctx, radarData, radarSubscriptionConfigPo)
	}

	for _, item := range radarData.List {
		//  `data_source` '数据类型是（WINBID:中标,DEVELOPER:客户,SUPPLIER:工程单位,SALE:在售项目,BUILDING:在建项目,LAND:拿地,PURCHASE:商机）',
		opptyStatusRequest := &businessOpportunityPb.GetOpptyStatusRequest{
			DataSource:   "",
			DataSourceId: item.Id,
			DetailPage:   false,
			FromDevice:   request.FromDevice,
		}

		var contactor []*businessOpportunityPb.ContactItem
		switch item.DataType {
		case "招标":
			opptyStatusRequest.DataSource = "PURCHASE"
			// 取招标负责人，直接放入数组第一个
			if item.PersonInChargeBidding != "" {
				bidChanger := businessOpportunityPb.ContactItem{}
				_ = json.Unmarshal([]byte(item.PersonInChargeBidding), &bidChanger)
				if bidChanger.SourceId != "" {
					if bidChanger.Name == "" {
						bidChanger.Name = "未知"
					}
					if bidChanger.PhoneNumber != "" {
						mobileViewPo, _ := f.opTelViewHistoryRepos.GetOpTelViewHistory(ctx, bidChanger.PhoneNumber, metaUserInfo.TenantUserUid)
						if mobileViewPo == nil || mobileViewPo.ViewTimes == 0 {
							//没看过，打码
							bidChanger.PhoneNumber = utils.GetMobileEncrypt(bidChanger.PhoneNumber)
						} else {
							//查看过，返回查看次数
							bidChanger.ViewTimes = mobileViewPo.ViewTimes
						}
					}

					contactor = append(contactor, &bidChanger)
				}
			}
		case "中标":
			opptyStatusRequest.DataSource = "WINBID"
		case "土地":
			opptyStatusRequest.DataSource = "LAND"
		case "在建":
			opptyStatusRequest.DataSource = "BUILDING"
		case "开盘":
			opptyStatusRequest.DataSource = "SALE"
		default:

		}
		//itemOpptyStatus
		opptyStatus, err := f.opptyStatusService.GetOpptyStatus(ctx, opptyStatusRequest)
		if err != nil {
			return nil, err
		}
		//

		var suppliers []*businessOpportunityPb.SupplierItem
		_ = json.Unmarshal([]byte(item.Suppliers), &suppliers)

		radarPbItem := &businessOpportunityPb.RadarOpptyItem{
			Uid:                     item.Id,
			OpptyType:               constants.GetOpptyTypeByName(item.DataType),
			BidSource:               item.BidSource,
			Title:                   item.Title,
			DeveloperName:           item.DeveloperName,
			DeveloperOrganizingCode: item.DeveloperOrganizingCode,
			Suppliers:               suppliers,
			PublishDate:             item.PublishDate,
			TakeLandDate:            item.TakeLandDate,
			OpeningDate:             item.OpeningDate,
			ProjectPlanBeginDate:    item.ProjectPlanBeginDate,
			ProjectRealityBeginDate: item.ProjectRealityBeginDate,
			ProjectPlanEndDate:      item.ProjectPlanEndDate,
			ProjectRealityEndDate:   item.ProjectRealityEndDate,
			OpptyStatus:             opptyStatus.StatusName,
			IsNew:                   item.IsNew,
			ContactNum:              item.DeveloperContactNum + item.SupplierContactNum + item.DeveloperCoopContactNum,
			Contactor:               contactor,
		}

		packingLabel(radarPbItem, item)
		radarPbResp.List = append(radarPbResp.List, radarPbItem)
	}

	// 组装联系人数据
	f.packingCompanyContract(ctx, radarPbResp, companyName2ContactList)

	return radarPbResp, nil
}

func packingLabel(radarPbItem *businessOpportunityPb.RadarOpptyItem, item *opensearch_remote.RadarItem) {
	for _, labelItem := range item.LandUsageLabel {
		if labelItem.Name != "" {
			radarPbItem.Label = append(radarPbItem.Label, labelItem.Name)
		}
	}
	if item.FitmentFeeLabel != "" {
		radarPbItem.Label = append(radarPbItem.Label, item.FitmentFeeLabel)
	}
	if item.ProjectTypeLabel != "" {
		radarPbItem.Label = append(radarPbItem.Label, item.ProjectTypeLabel)
	}

	if item.IsPriceGtAvg == "是" {
		radarPbItem.Label = append(radarPbItem.Label, "高端项目")
	} else if item.IsPriceGtAvg == "否" {
		radarPbItem.Label = append(radarPbItem.Label, "非高端项目")
	}

	for _, location := range item.Locations {
		if location.ProvinceName+location.CityName != "" {
			radarPbItem.Province = location.ProvinceName
			radarPbItem.City = location.CityName
			radarPbItem.ProvinceCode = location.ProvinceCode
			radarPbItem.CityCode = location.CityCode
		}
	}
}

func (f *subscriptionService) GetRadarPreCount(ctx context.Context, request *businessOpportunityPb.GetRadarPreCountRequest) (*businessOpportunityPb.GetRadarPreCountResponse, error) {
	stStr := time.Now().Add(-365 * 24 * time.Hour).Format("2006-01-02 15:04:05") //起始时间默认往前一年
	etStr := time.Now().Add(30 * 24 * time.Hour).Format("2006-01-02 15:04:05")   //结束时间默认往后一个月

	result, err := f.openSearchRepos.GetRadarList(ctx, &opensearch_remote.GetRadarListRequest{
		AreaCode:       request.AreaCodes,
		BidKeyword:     request.BidKeyword,
		WinbidKeyword:  request.WinbidKeyword,
		ExcludeKeyword: request.BidKeywordExclude,
		IsSaleOpen:     request.IsSaleOpen,
		BuildingType:   request.BuildingType,
		SaleType:       request.SaleType,
		LandUsageLabel: request.LandUsage,
		ProjectKeyword: request.ProjectKeyword,
		StartTime:      stStr,
		EndTime:        etStr,
		DataType:       nil,
		Page:           1,
		PageSize:       1,
		IsBuildingOpen: request.IsBuildingOpen,
		IsLandOpen:     request.IsLandOpen,
	})
	if err != nil {
		return nil, err
	}

	resp := &businessOpportunityPb.GetRadarPreCountResponse{}
	if result != nil {
		resp.Total = result.Total
	}
	return resp, nil
}

// SendRadarSubscriptionMessage 发送省市雷达订阅推送
func (f *subscriptionService) SendRadarSubscriptionMessage(ctxBackground context.Context) error {
	tenantList, err := f.gfyxUserServiceRepo.GetAllEfficientTenant(ctxBackground, &tenantPb.GetAllEfficientTenantRequest{})
	if err != nil {
		return err
	}
	var tenantCodes []string
	for _, tenantInfo := range tenantList.List {
		tenantCodes = append(tenantCodes, tenantInfo.Code)
	}
	// for test
	//tenantCodes = []string{"ompycgb"}
	// test end
	stark.Logger.Infof(ctxBackground, "SendRadarSubscriptionMessage,一共有%d个租户,列表为:%v", len(tenantCodes), tenantCodes)

	goNum := stark.Configer.(stark.ApolloConfigerIface).GetIntValue("radar_subscription.go_num", 1)
	if goNum <= 0 {
		goNum = 1
	}
	batchSize := (len(tenantCodes) / goNum) + 1
	for i := 0; i < goNum; i++ {
		startPos := i * batchSize
		endPos := (i + 1) * batchSize
		if startPos >= len(tenantCodes) {
			return nil
		}
		if endPos > len(tenantCodes) {
			endPos = len(tenantCodes)
		}
		stark.Logger.Infof(ctxBackground, "SendRadarSubscriptionMessage,第%d个协程消费下标【%d-%d】的租户，%v", i, startPos, endPos, tenantCodes[startPos:endPos])
		go f.sendMessageInBackground(ctxBackground, tenantCodes[startPos:endPos])
	}
	return nil
}

func (f *subscriptionService) sendMessageInBackground(ctxBackground context.Context, tenantCodes []string) {
	defer func() {
		if err := recover(); err != nil {
			stark.Logger.Infof(ctxBackground, "sendMessageInBackground-err: %+v", err)
		}
	}()
	msgClient := msg_center.NewClient(nil)
	pushOrderCode := stark.Configer.(stark.ApolloConfigerIface).GetStringValue("PushOrderCode.Radar", "")
	radarPageUrl := stark.Configer.(stark.ApolloConfigerIface).GetStringValue("radar_subscription.page_url", "")

	for _, tenantCode := range tenantCodes {
		startTime := time.Now()
		//1.获取db链接，保存链接到上下文
		//ctx := context.WithValue(ctxBackground, authorize.TENANT_CODE_KEY, tenantCode)
		ctx, _ := tenant_db.GetTenantBackgroundContext(ctxBackground, tenantCode)
		if (&tenant_db.TenantDB{}).GetTenantDB(ctx) == nil {
			stark.Logger.Errorf(ctx, "【sendMessageInBackground】租户:%s,GetTenantDB failed", tenantCode)
			continue
		}
		stark.Logger.Infof(ctx, "【sendMessageInBackground】租户:%s,推送开始时间:%s", tenantCode, startTime.Format("2006-01-02 15:04:05"))

		//2.查询用户订阅设置
		subConfigList, _ := f.radarSubscriptionConfigRepos.GetAllRadarSubscriptionConfig(ctx)
		stark.Logger.Infof(ctx, "【sendMessageInBackground】租户:%s,获取到用户订阅配置一共%d条", tenantCode, len(subConfigList))
		//3.查询es商机数据
		for i, config := range subConfigList {
			stark.Logger.Infof(ctx, "【sendMessageInBackground】租户:%s,正在推送第%d个用户GUID:%s", tenantCode, i, config.UserGuid)
			userInfo, err := f.userNewRepos.GetUserByCondition(ctx, map[string]interface{}{"uid": config.UserGuid})
			if err != nil || userInfo.Id == 0 {
				stark.Logger.Infof(ctx, "【sendMessageInBackground】租户:%s,第%d个用户GUID:%s，用户记录不存在", tenantCode, i, config.UserGuid)
				continue
			}
			pushLogRecord := &push_log.GfyxRadarSubscriptionPushLogPo{
				UserGuid:      userInfo.Uid,
				OpenId:        "",
				Email:         "",
				SearchRequest: "",
				SearchCount:   0,
				Status:        push_log.StatusDefault,
				FailureReason: "",
				RetryNum:      0,
				RetryStatus:   0,
				IsDeleted:     0,
				CreatedOn:     time.Now(),
				CreatedBy:     "定时任务",
				ModifiedOn:    time.Now(),
				ModifiedBy:    "定时任务",
			}

			requestParam := f.getSubscriptionRadarNum(ctx, config)
			searchBeforeTime := time.Now()
			radarData, err := f.openSearchRepos.GetRadarList(ctx, requestParam)
			pushLogRecord.SearchSpendTime = time.Now().Sub(searchBeforeTime).Milliseconds()
			requestParamBytes, _ := json.Marshal(requestParam)
			pushLogRecord.SearchRequest = string(requestParamBytes)
			if err != nil {
				stark.Logger.Errorf(ctx, "【sendMessageInBackground】租户:%s,第%d个用户GUID:%s，查询es报错:%s", tenantCode, i, config.UserGuid, err.Error())
				pushLogRecord.SearchRemark = err.Error()
				pushLogRecord.Status = push_log.StatusFailed
				_, _ = f.pushLogRepos.Create(ctx, pushLogRecord)
				continue
			}
			if radarData == nil || radarData.Total == 0 {
				pushLogRecord.SearchCount = 0
				stark.Logger.Infof(ctx, "【sendMessageInBackground】租户:%s,第%d个用户GUID:%s，查询es数据新增数据为空，不进行推送", tenantCode, i, config.UserGuid)
				_, _ = f.pushLogRepos.Create(ctx, pushLogRecord)
				continue
			}
			radarNum := radarData.Total
			if radarNum > 2000 {
				radarNum = 2000 //最多只推送2000条
			}
			pushLogRecord.SearchCount = radarData.Total //但是日志记录是原条数

			//4.获取用户推送设置，推送站内信、邮件
			pushConfig, _ := f.subscriptionPushConfigRepos.GetSubscriptionPushConfigByUser(ctx, config.UserGuid)
			if pushConfig.UserGuid == config.UserGuid {
				// 通过userGuid获取userId
				userInfo, _ = f.userNewRepos.GetUserByCondition(ctx, map[string]interface{}{"uid": config.UserGuid})
				if userInfo == nil || userInfo.Id == 0 {
					stark.Logger.Errorf(ctx, "【sendMessageInBackground】获取用户信息失败:userGuid=%s", config.UserGuid)
				} else {
					//数据库有用户推送设置的记录
					// 发送站内信
					msgInbox := &msg.GfyxMessageInboxPo{
						Id:           0,
						MessageType:  "线索订阅",
						Title:        fmt.Sprintf("尊敬的用户，今日为您推荐%d条合作机会", radarNum),
						Content:      fmt.Sprintf("尊敬的用户，今日为您推荐%d条合作机会", radarNum),
						SenderId:     0,
						ReceiverId:   userInfo.Id,
						IsReaded:     2,
						ReceivedTime: time.Now(),
						Link:         "",
						CreatedBy:    "",
						CreatedOn:    time.Now(),
						ModifiedBy:   "",
						ModifiedOn:   time.Now(),
						IsDeleted:    0,
					}

					if err = f.msgRepo.PushSiteMsg(ctx, msgInbox); err != nil {
						stark.Logger.Errorf(ctx, "【sendMessageInBackground】租户:%s,第%d个用户GUID:%s，发送站内信失败:%s", tenantCode, i, config.UserGuid, err.Error())
						fmt.Printf("【sendMessageInBackground】租户:%s,第%d个用户GUID:%s，发送站内信失败:%s\n", tenantCode, i, config.UserGuid, err.Error())
					} else {
						stark.Logger.Infof(ctx, "【sendMessageInBackground】租户:%s,第%d个用户GUID:%s，发送站内信成功", tenantCode, i, config.UserGuid)
						fmt.Printf("【sendMessageInBackground】租户:%s,第%d个用户GUID:%s，发送站内信成功\n", tenantCode, i, config.UserGuid)
					}
				}

				// 发送邮件
				if pushConfig.Email != "" {
					pushLogRecord.Email = pushConfig.Email
					content := map[string]interface{}{
						"T1": "线索订阅",
						"T2": fmt.Sprintf("<div>尊敬的用户，今日为您推荐%d条合作机会，请及时<a href=\"%s\">查看</a>！</div>", radarNum, radarPageUrl),
					}
					contentStr, _ := json.Marshal(content)
					msgStd := &msg_center.MsgBody{
						PushOrderCode: pushOrderCode,
						Email: &msg_center.MsgContent{
							ReceiverIds: []string{pushConfig.Email},
							Content:     string(contentStr),
							TryTimes:    0,
							ConfirmUrl:  "",
							CallbackUrl: "",
						},
					}
					if err = msgClient.Push(ctx, msgStd); err != nil {
						pushLogRecord.Status = push_log.StatusFailed
						pushLogRecord.FailureReason = err.Error()
						stark.Logger.Errorf(ctx, "【sendMessageInBackground】租户:%s,第%d个用户GUID:%s，发送邮件消息失败:%s", tenantCode, i, config.UserGuid, err.Error())
						fmt.Printf("【sendMessageInBackground】租户:%s,用户:%s,发送邮件消息失败:%s\n", tenantCode, config.UserGuid, err.Error())
					} else {
						stark.Logger.Infof(ctx, "【sendMessageInBackground】租户:%s,第%d个用户GUID:%s,发送邮件消息成功", tenantCode, i, config.UserGuid)
						fmt.Printf("【sendMessageInBackground】租户:%s,用户:%s,发送邮件消息成功\n", tenantCode, config.UserGuid)
					}
				}
			}
			//5.获取用户openid，推送微信
			userBindInfo, _ := f.userBindRepos.GetUserBind(ctx, config.UserGuid)
			if userBindInfo.OpenId != "" {
				pushLogRecord.OpenId = userBindInfo.OpenId
				content := map[string]interface{}{
					"T1":  "新线索通知",
					"T2":  fmt.Sprintf("今日新增%d条合作机会", radarNum),
					"T3":  utils.TimeToString(time.Now()),
					"T4":  fmt.Sprintf("【%s】订阅通知", userInfo.Name),
					"url": "pages/index/index?tab=business-recommend",
				}
				contentStr, _ := json.Marshal(content)
				msgStd := &msg_center.MsgBody{
					PushOrderCode: pushOrderCode,
					Wx: &msg_center.MsgContent{
						ReceiverIds: []string{userBindInfo.OpenId},
						Content:     string(contentStr),
						TryTimes:    0,
						ConfirmUrl:  "",
						CallbackUrl: "",
					},
				}
				if err = msgClient.Push(ctx, msgStd); err != nil {
					pushLogRecord.Status = push_log.StatusFailed
					pushLogRecord.FailureReason = err.Error()
					stark.Logger.Errorf(ctx, "【sendMessageInBackground】租户:%s,第%d个用户GUID:%s，发送微信公众号消息失败:%s", tenantCode, i, config.UserGuid, err.Error())
					fmt.Printf("【sendMessageInBackground】租户:%s,用户:%s,发送微信公众号消息失败:%s\n", tenantCode, config.UserGuid, err.Error())
				} else {
					stark.Logger.Infof(ctx, "【sendMessageInBackground】租户:%s,第%d个用户GUID:%s，发送微信公众号消息成功", tenantCode, i, config.UserGuid)
					fmt.Printf("【sendMessageInBackground】租户:%s,用户:%s,发送微信公众号消息成功\n", tenantCode, config.UserGuid)
				}
			}

			//6.记录用户推送日志
			if pushLogRecord.Status != push_log.StatusFailed {
				pushLogRecord.Status = push_log.StatusSucceed
			}
			_, _ = f.pushLogRepos.Create(ctx, pushLogRecord)
		}
		stark.Logger.Infof(ctx, "【sendMessageInBackground】租户:%s,推送完成时间:%s,耗时:%d毫秒", tenantCode, time.Now().Format("2006-01-02 15:04:05"), time.Now().Sub(startTime).Milliseconds())
		//6.释放db链接
	}
}

func (f *subscriptionService) getSubscriptionRadarNum(_ context.Context, config *radar2.GfyxRadarSubscriptionConfig) *opensearch_remote.GetRadarListRequest {
	yesterday := time.Now().Add(-24 * time.Hour).Format("2006-01-02")
	requestParam := &opensearch_remote.GetRadarListRequest{
		StartTime:      yesterday + " 00:00:00",
		EndTime:        yesterday + " 23:59:59",
		DataType:       nil,
		Page:           1,
		PageSize:       1,
		IsBuildingOpen: config.IsBuildingOpen,
		IsLandOpen:     config.IsLandOpen,
		IsSaleOpen:     config.IsSaleOpen,
	}

	if config.AreaCode != "" {
		requestParam.AreaCode = strings.Split(config.AreaCode, ",")
	}
	if config.BidKeyword != "" {
		requestParam.BidKeyword = strings.Split(config.BidKeyword, ",")
	}
	if config.WinbidKeyword != "" {
		requestParam.WinbidKeyword = strings.Split(config.WinbidKeyword, ",")
	}
	if config.BidKeywordExclude != "" {
		requestParam.ExcludeKeyword = strings.Split(config.BidKeywordExclude, ",")
	}
	if config.BuildingType != "" {
		requestParam.BuildingType = strings.Split(config.BuildingType, ",")
	}
	if config.SaleType != "" {
		requestParam.SaleType = strings.Split(config.SaleType, ",")
	}
	if config.LandUsage != "" {
		requestParam.LandUsageLabel = strings.Split(config.LandUsage, ",")
	}
	if config.ProjectKeyword != "" {
		requestParam.ProjectKeyword = strings.Split(config.ProjectKeyword, ",")
	}

	return requestParam
}

// UpdateOpenIdSubscribeStatus 更新用户“云采购平台公众号”的关注状态
func (f *subscriptionService) UpdateOpenIdSubscribeStatus(ctxBackground context.Context) error {
	tenantList, err := f.gfyxUserServiceRepo.GetAllEfficientTenant(ctxBackground, &tenantPb.GetAllEfficientTenantRequest{})
	if err != nil {
		return err
	}
	var tenantCodes []string
	for _, tenantInfo := range tenantList.List {
		tenantCodes = append(tenantCodes, tenantInfo.Code)
	}
	stark.Logger.Infof(ctxBackground, "UpdateOpenIdSubscribeStatus,一共有%d个租户,列表为:%v", len(tenantCodes), tenantCodes)

	goNum := stark.Configer.(stark.ApolloConfigerIface).GetIntValue("radar_subscription.go_num", 1)
	if goNum <= 0 {
		goNum = 1
	}
	batchSize := (len(tenantCodes) / goNum) + 1
	for i := 0; i < goNum; i++ {
		startPos := i * batchSize
		endPos := (i + 1) * batchSize
		if startPos >= len(tenantCodes) {
			return nil
		}
		if endPos > len(tenantCodes) {
			endPos = len(tenantCodes)
		}
		stark.Logger.Infof(ctxBackground, "SendRadarSubscriptionMessage,第%d个协程消费下标【%d-%d】的租户，%v", i, startPos, endPos, tenantCodes[startPos:endPos])
		go f.updateUserBind(ctxBackground, tenantCodes[startPos:endPos])
	}
	return nil
}
func (f *subscriptionService) updateUserBind(ctxBackground context.Context, tenantCodes []string) {
	defer func() {
		if err := recover(); err != nil {
			stark.Logger.Infof(ctxBackground, "updateUserBind-err: %+v", err)
		}
	}()

	for _, tenantCode := range tenantCodes {
		startTime := time.Now()

		//1.获取db链接，保存链接到上下文
		ctx, err := tenant_db.GetTenantBackgroundContext(ctxBackground, tenantCode)
		if err != nil {
			stark.Logger.Errorf(ctx, "【updateUserBind】租户:%s,获取db链接失败:%s", tenantCode, err.Error())
			fmt.Println("租户code：", tenantCode, ",获取db链接失败：", err.Error())
			continue
		}
		if (&tenant_db.TenantDB{}).GetTenantDB(ctx) == nil {
			stark.Logger.Errorf(ctx, "【updateUserBind】租户:%s,GetTenantDB failed", tenantCode)
			continue
		}
		stark.Logger.Infof(ctx, "【updateUserBind】租户:%s,开始时间:%s", tenantCode, startTime.Format("2006-01-02 15:04:05"))
		stark.Logger.Infof(ctx, "【updateUserBind】租户:%s,获取db链接成功", tenantCode)
		fmt.Println("租户code：", tenantCode, ",获取db链接成功")

		//2.用户绑定openid列表
		userBindList, _ := f.userBindRepos.GetUserBindAll(ctx)
		stark.Logger.Infof(ctx, "【updateUserBind】租户:%s,获取到用户openid绑定数量，一共%d条", tenantCode, len(userBindList))
		for _, v := range userBindList {
			if v.OpenId != "" {
				getUnionIdRequest := &GetUnionIdRequest{
					AppId:  stark.Configer.(stark.ApolloConfigerIface).GetStringValue(constants.YcgGzhAppId, "wx26f077d201e7c978"),
					OpenId: v.OpenId,
				}
				getUnionIdRequestMap, err := simplecopier.StructToMapByJsonTag(getUnionIdRequest)
				if err != nil {
					stark.Logger.Error(ctx, "结构体转map异常,err:%s", err.Error())
				}
				resultDataUnionId := &OpenApiUserSubscribeResponse{}
				_, _, errsGetUnionId := http_client.NewOpenApiHttpClient().Post(ctx, constants.OpenApiPathGetUserSubscriptionInfoByOpenId, getUnionIdRequestMap, map[string]string{}).EndStruct(&resultDataUnionId)
				if len(errsGetUnionId) > 0 {
					stark.Logger.Error(ctx, "获取union_api接口异常,接口:%s,err:%s", constants.OpenApiPathGetUserSubscriptionInfoByOpenId, errsGetUnionId[0].Error())
				}
				if resultDataUnionId.Success && resultDataUnionId.Data.IsSubscribe == 0 {
					oldOpenId := v.OpenId
					v.OpenId = ""
					v.ModifiedBy = "用户取关公众号"
					err := f.userBindRepos.SaveUserBind(ctx, v)
					if err != nil {
						stark.Logger.Error(ctx, "更新user_bind,err:%s", err.Error())
					}
					stark.Logger.Infof(ctx, "【updateUserBind】租户:%s,用户取关公众号，将openid置空，id:%d,用户id:%s,原openid:%s", tenantCode, v.Id, v.UserGuid, oldOpenId)
				}
			}

		}

	}

}
